﻿using CNative.Utilities;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Dynamic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Threading;
using System.Threading.Tasks;

namespace CNative
{
    public static partial class Utils
    {

        /// <summary>
        /// 转换为字符串,空对象转换为空字符串
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static string NullToStr(this object obj)
        {
            return Utilities.FuncStr.NullToStr(obj);
        }

        /// <summary>
        /// 转换为int,空对象转换为0
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static int NullToInt(this object obj)
        {
            return Utilities.FuncStr.NullToInt(obj);
        }

        /// <summary>
        /// 判断字符串是否数字
        /// </summary>
        /// <returns>返回是否</returns>
        public static bool IsNumeric(this object str)
        {
            return Utilities.FuncStr.IsNumeric(str);
        }

        /// <summary>
        /// 转换为Decimal,空对象转换为0.0
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static Decimal NullToDecimal(this object obj)
        {
            return Utilities.FuncStr.NullToDecimal(obj);
        }
        /// <summary>
        /// 转换为double,空对象转换为0.0
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static double NullToDouble(this object obj)
        {
            return Utilities.FuncStr.NullToDouble(obj);
        }

        ///// <summary>
        ///// System.Windows.Forms.Keys类型转换为String
        ///// </summary>
        ///// <param name="k"></param>
        ///// <returns></returns>
        //public static string KeyCodeToStr(this System.Windows.Forms.Keys k)
        //{
        //    return Utilities.FuncStr.KeyCodeToStr(k);
        //}


        /// <summary>
        /// 判断是否为Null或者空
        /// </summary>
        /// <param name="obj">对象</param>
        /// <returns></returns>
        public static bool IsNullOrEmpty(this object obj)
        {
            return obj.IsNullOrEmpty_();
            if (obj == null || obj == DBNull.Value)
            {
                return true;
            }
            else
            {
                string objStr = obj.ToString();
                return string.IsNullOrEmpty(objStr);
            }
        }
        /// <summary>
        /// 判断是否不为Null或者空
        /// </summary>
        /// <param name="obj">对象</param>
        /// <returns></returns>
        public static bool IsNotNullOrEmpty(this object obj)
        {
            return !IsNullOrEmpty(obj);
        }


        /// <summary>
        /// 初始化时间默认值
        /// </summary>
        /// <param name="obj">对象</param>
        /// <returns></returns>
        public static T InitDateTime<T>(this T obj) where T : class
        {
            obj.GetType().GetProperties().ForEach(aProperty =>
            {
                if (aProperty.PropertyType == typeof(DateTime))
                {
                    aProperty.SetValue(obj, DateTime.Now, BindingFlags.GetField | BindingFlags.GetProperty, null, null, CultureInfo.CurrentCulture);
                }
            });

            return obj;
        }

        /// <summary>
        /// 获取某属性值
        /// </summary>
        /// <param name="obj">对象</param>
        /// <param name="propertyName">属性名</param>
        /// <returns></returns>
        public static object GetPropertyValue(this object obj, string propertyName)
        {
            if (TryGetPropertyValue(obj, propertyName, out object val))
                return val;
            return null;
        }
        /// <summary>
        /// 获取某属性值
        /// </summary>
        /// <param name="obj">对象</param>
        /// <param name="propertyName">属性名</param>
        /// <returns></returns>
        public static bool TryGetPropertyValue(this object obj, string propertyName, out object val)
        {
            val = null;
            if (obj == null || obj == DBNull.Value || propertyName.IsNullOrEmpty())
                return false;
            var pre = obj.GetType().GetProperty(propertyName,
                BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static);
            if (pre != null && pre.CanRead)
            {
                val = pre.GetValue(obj, null);
                return true;
            }
            else
            {
                var filed = obj.GetType().GetField(propertyName,
                    BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static);
                if (filed != null)
                {
                    val = filed.GetValue(obj);
                    return true;
                }
            }

            return false;
        }

        /// <summary>
        /// 获取某属性值
        /// </summary>
        /// <param name="obj">对象</param>
        /// <param name="propertyName">属性名</param>
        /// <param name="value">值</param>
        /// <returns></returns>
        public static bool SetPropertyValue(this object obj, string propertyName, object value)
        {
            if (obj == null || obj == DBNull.Value || propertyName.IsNullOrEmpty())
                return false;
            var pre = obj.GetType().GetProperty(propertyName,
                BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static);
            if (pre != null && pre.CanWrite)
            {
                //pre.SetValue(obj, value, BindingFlags.GetField | BindingFlags.GetProperty, null, null, CultureInfo.CurrentCulture);
                try
                {
                    var val = value.ChangeType(pre.PropertyType);
                    if (val != null) value = val;
                }
                catch { }
                pre.SetValue(obj, value, null);
                return true;
            }
            else
            {
                var filed = obj.GetType().GetField(propertyName,
                    BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static);
                if (filed != null)
                {
                    filed.SetValue(obj, value);
                    return true;
                }
            }

            return false;
        }

        /// <summary>
        /// 获取对象指定属性类别的所有属性
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="attributeType"></param>
        /// <returns></returns>
        public static List<PropertyInfo> GetPropertys(this object obj, Type attributeType = null)
        {
            if (obj == null || obj == DBNull.Value)
                return new List<PropertyInfo>();
            var properties = obj.GetType()
                .GetProperties()
                 .Where(x => attributeType == null || x.GetCustomAttributes(true).Select(o => o.GetType().FullName).Contains(attributeType.FullName))
                .ToList();
            return properties;
        }

        /// <summary>
        /// 返回两个对象有差异的属性值
        /// </summary>
        /// <param name="newObj">新对象</param>
        /// <param name="oldObj">老对象</param>
        /// <returns>key:属性名称;value:差异描述</returns>
        public static Dictionary<string, string> GetPropertyDiff(this object newObj, object oldObj)
        {
            var diff = new Dictionary<string, string>();
            if (newObj.IsNullOrEmpty() || oldObj.IsNullOrEmpty()
                || newObj.GetHashCode() == oldObj.GetHashCode())
                return diff;

            var properties = newObj.GetType().GetProperties().ToList();
            properties.ForEach(pro =>
            {
                var newValue = pro.GetValue(newObj, null).NullToStr();//新对象属性值
                var oldValue = oldObj.GetPropertyValue(pro.Name).NullToStr();//老对象属性值
                if (newValue != oldValue)
                {
                    diff[pro.Name] = oldValue + " => " + newValue;
                }
            });
            return diff;
        }

        /// <summary>
        /// 浅复制相同类型对象属性
        /// </summary>
        /// <param name="fromObj">源对象</param>
        /// <param name="toObj">目标对象</param>
        /// <returns>目标对象</returns>
        public static Tclass ApplyTo<Tclass>(this Tclass fromObj, Tclass toObj)
        {
            var diff = new Dictionary<string, string>();
            if (fromObj.IsNullOrEmpty() || toObj.IsNullOrEmpty()
                || fromObj.GetHashCode() == toObj.GetHashCode())
                return toObj;

            var properties = fromObj.GetType().GetProperties().ToList();
            properties.ForEach(pro =>
            {
                if (pro.CanWrite)
                    pro.SetValue(toObj, pro.GetValue(fromObj, null), null);
            });
            return toObj;
        }
        /// <summary>
        /// 浅复制对象属性
        /// </summary>
        /// <param name="fromObj">源对象</param>
        /// <param name="toObj">目标对象</param>
        /// <returns>目标对象</returns>
        public static object ApplyObjectTo(this object fromObj, object toObj)
        {
            var diff = new Dictionary<string, string>();
            if (fromObj.IsNullOrEmpty() || toObj.IsNullOrEmpty()
                || fromObj.GetHashCode() == toObj.GetHashCode())
                return toObj;

            var properties = fromObj.GetType().GetProperties().ToList();
            properties.ForEach(pro =>
            {
                toObj.SetPropertyValue(pro.Name, pro.GetValue(fromObj, null));
            });
            return toObj;
        }
        /// <summary>
        /// 返回两个对象有差异的属性值
        /// </summary>
        /// <param name="newObj">新对象</param>
        /// <param name="oldObj">老对象</param>
        /// <returns>差异属性名称集合</returns>
        public static List<string> GetPropertyDiffList(this object newObj, object oldObj)
        {
            return GetPropertyDiff(newObj, oldObj).Keys.ToList();
        }


        ///// <summary>
        ///// 深度复制对象
        ///// </summary>
        ///// <typeparam name="T">类型</typeparam>
        ///// <param name="obj">对象</param>
        ///// <returns></returns>
        //public static T DeepClone<T>(this T obj) where T : class
        //{
        //    if (obj == null)
        //        return null;

        //    return obj.ToJson().ToObject<T>();
        //}

        /// <summary>
        /// 深度复制集合
        /// </summary>
        /// <typeparam name="TIn">类型</typeparam>
        /// <param name="tIn"></param>
        /// <returns></returns>
        public static List<TIn> DeepClone<TIn>(this List<TIn> tIn)
        {
            return Utilities.Function.FuncClone<TIn>.Clone(tIn).CastToList<TIn>(); ;
        }

        /// <summary>
        /// 深度复制对象
        /// </summary>
        /// <typeparam name="TIn">类型</typeparam>
        /// <param name="tIn"></param>
        /// <returns></returns>
        public static TIn DeepClone<TIn>(this TIn tIn)
        {
            return Utilities.Function.FuncClone<TIn>.Clone(tIn);
        }

        /// <summary>
        /// 对象转JSON
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string ToJson(this object value)
        {
            return Utilities.JsonHelper.SerializeObjectToJson(value);
        }
        /// <summary>
        ///JSON转对象
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static T JsonToObject<T>(this string value)
        {
            return Utilities.JsonHelper.DeserializeObjectByJson<T>(value);
        }

        public static string GetExceptionMessage(this Exception exception)
        {
            if (exception == null)
                return string.Empty;

            var message = exception.Message;
            if (exception.InnerException != null)
            {
                message += "|InnerException:" + GetExceptionMessage(exception.InnerException);
            }
            return message;
        }

        /// <summary>
        /// 将 DateTimeOffset 转换成 DateTime
        /// </summary>
        /// <param name="dateTime"></param>
        /// <returns></returns>
        public static DateTime ConvertToDateTime(this DateTimeOffset dateTime)
        {
            if (dateTime.Offset.Equals(TimeSpan.Zero))
                return dateTime.UtcDateTime;
            else if (dateTime.Offset.Equals(TimeZoneInfo.Local.GetUtcOffset(dateTime.DateTime)))
                return DateTime.SpecifyKind(dateTime.DateTime, DateTimeKind.Local);
            else
                return dateTime.DateTime;
        }

        /// <summary>
        /// 将 DateTime 转换成 DateTimeOffset
        /// </summary>
        /// <param name="dateTime"></param>
        /// <returns></returns>
        public static DateTimeOffset ConvertToDateTimeOffset(this DateTime dateTime)
        {
            return DateTime.SpecifyKind(dateTime, DateTimeKind.Local);
        }

        /// <summary>
        /// 判断是否是富基元类型
        /// </summary>
        /// <param name="type">类型</param>
        /// <returns></returns>
        public static bool IsRichPrimitive(this Type type)
        {
#if !net40
            // 处理元组类型
            if (type.IsValueTuple()) return false;
#endif
            // 处理数组类型，基元数组类型也可以是基元类型
            if (type.IsArray) return type.GetElementType().IsRichPrimitive();

            // 基元类型或值类型或字符串类型
            if (type.IsPrimitive || type.IsValueType || type == typeof(string)) return true;

            if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
#if net40
                return type.GetGenericArguments()[0].IsRichPrimitive();
#else
                return type.GenericTypeArguments[0].IsRichPrimitive();
#endif
            return false;
        }

        /// <summary>
        /// 合并两个字典
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dic">字典</param>
        /// <param name="newDic">新字典</param>
        /// <returns></returns>
        public static Dictionary<string, T> AddOrUpdate<T>(this Dictionary<string, T> dic, Dictionary<string, T> newDic)
        {
            foreach (var key in newDic.Keys)
            {
                if (dic.ContainsKey(key))
                    dic[key] = newDic[key];
                else
                    dic.Add(key, newDic[key]);
            }

            return dic;
        }
#if !net40
        /// <summary>
        /// 判断是否是元组类型
        /// </summary>
        /// <param name="type">类型</param>
        /// <returns></returns>
        public static bool IsValueTuple(this Type type)
        {
            return type.ToString().StartsWith(typeof(ValueTuple).FullName);
        }
#endif

        /// <summary>
        /// 判断方法是否是异步
        /// </summary>
        /// <param name="method">方法</param>
        /// <returns></returns>
        public static bool IsAsync(this MethodInfo method)
        {
            return method.ReturnType.IsAsync();
        }

        /// <summary>
        /// 判断类型是否是异步类型
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static bool IsAsync(this Type type)
        {
            return type.ToString().StartsWith(typeof(Task).FullName);
        }

        /// <summary>
        /// 判断类型是否实现某个泛型
        /// </summary>
        /// <param name="type">类型</param>
        /// <param name="generic">泛型类型</param>
        /// <returns>bool</returns>
        public static bool HasImplementedRawGeneric(this Type type, Type generic)
        {
            // 检查接口类型
            var isTheRawGenericType = type.GetInterfaces().Any(IsTheRawGenericType);
            if (isTheRawGenericType) return true;

            // 检查类型
            while (type != null && type != typeof(object))
            {
                isTheRawGenericType = IsTheRawGenericType(type);
                if (isTheRawGenericType) return true;
                type = type.BaseType;
            }

            return false;

            // 判断逻辑
            bool IsTheRawGenericType(Type type1) => generic == (type1.IsGenericType ? type1.GetGenericTypeDefinition() : type1);
        }

        /// <summary>
        /// 判断是否是匿名类型
        /// </summary>
        /// <param name="obj">对象</param>
        /// <returns></returns>
        public static bool IsAnonymous(this object obj)
        {
            var type = obj.GetType();

            return Attribute.IsDefined(type, typeof(CompilerGeneratedAttribute), false)
                   && type.IsGenericType && type.Name.Contains("AnonymousType")
                   && (type.Name.StartsWith("<>") || type.Name.StartsWith("VB$"))
                   && type.Attributes.HasFlag(TypeAttributes.NotPublic);
        }

        /// <summary>
        /// 获取所有祖先类型
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static IEnumerable<Type> GetAncestorTypes(this Type type)
        {
            var ancestorTypes = new List<Type>();
            while (type != null && type != typeof(object))
            {
                if (IsNoObjectBaseType(type))
                {
                    var baseType = type.BaseType;
                    ancestorTypes.Add(baseType);
                    type = baseType;
                }
                else break;
            }

            return ancestorTypes;

            bool IsNoObjectBaseType(Type type1) => type1.BaseType != typeof(object);
        }

        /// <summary>
        /// 获取方法真实返回类型
        /// </summary>
        /// <param name="method"></param>
        /// <returns></returns>
        public static Type GetMethodRealReturnType(this MethodInfo method)
        {
            // 判断是否是异步方法
            var isAsyncMethod = method.IsAsync();

            // 获取类型返回值并处理 Task 和 Task<T> 类型返回值
            var returnType = method.ReturnType;
#if net40
            return isAsyncMethod ? (returnType.GetGenericArguments().FirstOrDefault() ?? typeof(void)) : returnType;
#else
            return isAsyncMethod ? (returnType.GenericTypeArguments.FirstOrDefault() ?? typeof(void)) : returnType;
#endif
        }

        /// <summary>
        /// 返回异步类型
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="realType"></param>
        /// <returns></returns>
        public static object ToTaskResult(this object obj, Type realType)
        {
#if net40
            return obj;
#else
            return typeof(Task).GetMethod(nameof(Task.FromResult)).MakeGenericMethod(realType).Invoke(null, new object[] { obj });
#endif
        }

        /// <summary>
        /// 首字母大写
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static string ToTitleCase(this string str)
        {
            return Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase(str);
        }

        /// <summary>
        /// 将一个对象转换为指定类型
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static T ChangeType<T>(this object obj)
        {
            return (T)ChangeType(obj, typeof(T));
        }

        /// <summary>
        /// 将一个对象转换为指定类型
        /// </summary>
        /// <param name="obj">待转换的对象</param>
        /// <param name="type">目标类型</param>
        /// <returns>转换后的对象</returns>
        public static object ChangeType(this object obj, Type type)
        {
            if (type == null) return obj;
            if (obj == null) return type.IsValueType ? Activator.CreateInstance(type) : null;

            var underlyingType = Nullable.GetUnderlyingType(type);
            if (type.IsAssignableFrom(obj.GetType())) return obj;
            else if ((underlyingType ?? type).IsEnum)
            {
                if (underlyingType != null && string.IsNullOrEmpty(obj.ToString())) return null;
                else return Enum.Parse(underlyingType ?? type, obj.ToString());
            }
            // 处理DateTime -> DateTimeOffset 类型
            else if (obj.GetType().Equals(typeof(DateTime)) && (underlyingType ?? type).Equals(typeof(DateTimeOffset)))
            {
                return ((DateTime)obj).ConvertToDateTimeOffset();
            }
            // 处理 DateTimeOffset -> DateTime 类型
            else if (obj.GetType().Equals(typeof(DateTimeOffset)) && (underlyingType ?? type).Equals(typeof(DateTime)))
            {
                return ((DateTimeOffset)obj).ConvertToDateTime();
            }
            else if (typeof(IConvertible).IsAssignableFrom(underlyingType ?? type))
            {
                try
                {
                    return Convert.ChangeType(obj, underlyingType ?? type, null);
                }
                catch
                {
                    return underlyingType == null ? Activator.CreateInstance(type) : null;
                }
            }
            else
            {
                var converter = TypeDescriptor.GetConverter(type);
                if (converter.CanConvertFrom(obj.GetType())) return converter.ConvertFrom(obj);

                var constructor = type.GetConstructor(Type.EmptyTypes);
                if (constructor != null)
                {
                    var o = constructor.Invoke(null);
                    var propertys = type.GetProperties();
                    var oldType = obj.GetType();

                    foreach (var property in propertys)
                    {
                        var p = oldType.GetProperty(property.Name);
                        if (property.CanWrite && p != null && p.CanRead)
                        {
                            property.SetValue(o, ChangeType(p.GetValue(obj, null), property.PropertyType), null);
                        }
                    }
                    return o;
                }
            }
            return obj;
        }

        ///// <summary>
        ///// 通用类型转换 Convert.ChangeType
        ///// </summary>
        ///// <param name="value"></param>
        ///// <param name="type"></param>
        ///// <returns></returns>
        //public static object ChanageType(this object value, Type type)
        //{
        //    if (value == null && type.IsGenericType) return Activator.CreateInstance(type);
        //    if (value == null) return null;
        //    if (type == value.GetType()) return value;
        //    if (type == typeof(string)) return value.NullToStr();
        //    //if (type.IsEnum)
        //    //{
        //    //    if (value is string)
        //    //        return Enum.Parse(type, value as string);
        //    //    else
        //    //        return Enum.ToObject(type, value);
        //    //}
        //    if (!type.IsInterface && type.IsGenericType)
        //    {
        //        Type innerType = type.GetGenericArguments()[0];
        //        object innerValue = ChanageType(value, innerType);
        //        return Activator.CreateInstance(type, new object[] { innerValue });
        //    }
        //    if (value is string && type == typeof(Guid)) return new Guid(value as string);
        //    if (value is string && type == typeof(Version)) return new Version(value as string);
        //    if (value.GetType().IsClass && !value.GetType().Equals(typeof(string))) return ChanageObjectType(value, type);
        //    if (!(value is IConvertible)) return value;
        //    //return Convert.ChangeType(value, type);
        //    return Utilities.FuncTable2Entity.ConvertType(value, type);
        //}
        ///// <summary>
        ///// 通用类型转换 Convert.ChangeType
        ///// </summary>
        ///// <typeparam name="T">返回类型</typeparam>
        ///// <param name="value"></param>
        ///// <returns></returns>
        //public static T ChanageType<T>(this object value)
        //{
        //    if (ChanageType(value, typeof(T)) is T ret) return ret;
        //    return default(T);
        //}
        /// <summary>
        ///  Deserializes the JSON to the specified .NET type.
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public static object ChanageObjectType(this object obj, Type type)
        {
            if (obj?.GetType().IsClass == true && obj?.GetType().Equals(typeof(string)) == false && !type.Equals(typeof(void)))
                return Newtonsoft.Json.JsonConvert.DeserializeObject(Newtonsoft.Json.JsonConvert.SerializeObject(obj), type);
            else return obj;
        }
        /// <summary>
        /// 将对象转字典集合
        /// </summary>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static Dictionary<string, TValue> ToDictionary<TValue>(this object obj)
        {
            var dic = new Dictionary<string, TValue>();

            // 如果对象为空，则返回空字典
            if (obj == null) return dic;

            // 如果不是类类型或匿名类型，则返回空字典
            var type = obj.GetType();
            if (!(type.IsClass || type.IsAnonymous())) return dic;

            // 获取所有属性
            var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);

            // 如果实例公开属性为空，则返回空字典
            if (properties.Length == 0) return dic;

            // 遍历公开属性
            foreach (var property in properties)
            {
                var value = property.GetValue(obj, null);
                dic.Add(property.Name, value.ChangeType<TValue>());
            }

            return dic;
        }
        #region ToJObject
        /// <summary>  
        /// DataTable转成Newtonsoft.Json.Linq.JArray   
        /// </summary>  
        /// <param name="jsonName"></param>  
        /// <param name="dt"></param>  
        /// <returns></returns>  
        public static dynamic ToJObject(this DataTable dt, string jsonName = "", bool isNameNullUseTableName = false)
        {
            var Json = new Newtonsoft.Json.Linq.JArray();
            if (dt == null) return Json;

            if (string.IsNullOrEmpty(jsonName) && isNameNullUseTableName)
                jsonName = dt.TableName;
            //---------------------------------------------------------------------------------------------------------
            if (dt.Rows.Count > 0)
            {
                for (int i = 0; i < dt.Rows.Count; i++)
                {
                    Json.Add(ToJObject(dt.Rows[i], ""));//, fillerCol , params string[] fillerCol
                }
            }
            //---------------------------------------------------------------------------------------------------------
            if (string.IsNullOrEmpty(jsonName))
            {
                return Json;
            }
            else
            {
                var ret = new Newtonsoft.Json.Linq.JObject();
                ret[jsonName] = Json;// new Newtonsoft.Json.Linq.JValue(dr[j]);
                return ret;
            }
        }
        /// <summary>  
        /// DataRow转成 Newtonsoft.Json.Linq.JObject   
        /// </summary>  
        /// <param name="jsonName"></param>  
        /// <param name="dt"></param>  
        /// <returns></returns>  
        public static Newtonsoft.Json.Linq.JObject ToJObject(this DataRow dr, string jsonName = "")
        {
            var Json = new Newtonsoft.Json.Linq.JObject();
            if (dr == null) return Json;

            //var list = new List<string>(fillerCol);, params string[] fillerCol
            //---------------------------------------------------------------------------------------------------------
            for (int j = 0; j < dr.Table.Columns.Count; j++)
            {
                // if (list?.Exists(s => s.ToLower() == dr.Table.Columns[j].ColumnName.ToLower()) == true)
                //     continue;
                var obj = dr[j];
                if (obj.NullToStr().IsJson())
                {
                    obj = Newtonsoft.Json.JsonConvert.DeserializeObject(dr[j].NullToStr());
                    Json[dr.Table.Columns[j].ColumnName] = obj as Newtonsoft.Json.Linq.JToken;// new Newtonsoft.Json.Linq.JValue(obj);
                }
                else
                {
                    Json[dr.Table.Columns[j].ColumnName] = new Newtonsoft.Json.Linq.JValue(obj);
                }
            }
            //---------------------------------------------------------------------------------------------------------
            if (string.IsNullOrEmpty(jsonName))
            {
                return Json;
            }
            else
            {
                var ret = new Newtonsoft.Json.Linq.JObject();
                ret[jsonName] = Json;// new Newtonsoft.Json.Linq.JValue(dr[j]);
                return ret;
            }
        }
        //==============================================================================================================
        /// <summary>  
        /// DataTable转成dynamic
        /// </summary>  
        /// <param name="jsonName"></param>  
        /// <param name="dt"></param>  
        /// <returns></returns>  
        public static dynamic ToDynamic(this DataTable dt, string jsonName = "", bool isNameNullUseTableName = false)
        {
            var expando = new List<MyDynamicObject>();
            if (dt == null) return expando;

            if (string.IsNullOrEmpty(jsonName) && isNameNullUseTableName)
                jsonName = dt.TableName;
            //---------------------------------------------------------------------------------------------------------
            if (dt.Rows.Count > 0)
            {
                for (int i = 0; i < dt.Rows.Count; i++)
                {
                    expando.Add(ToDynamic(dt.Rows[i], ""));
                }
            }
            //---------------------------------------------------------------------------------------------------------
            if (string.IsNullOrEmpty(jsonName))
            {
                return expando;
            }
            else
            {
                var dyret = new MyDynamicObject();
                //dynamic ret = new ExpandoObject();
                //IDictionary<string, object> dyret = ret;
                dyret[jsonName] = expando;
                return dyret;
            }
        }
        /// <summary>  
        /// DataRow转成 dynamic
        /// </summary>  
        /// <param name="jsonName"></param>  
        /// <param name="dr"></param>  
        /// <returns></returns>  
        public static dynamic ToDynamic(this DataRow dr, string jsonName = "")
        {
            if (dr == null)
                return new { };

            dynamic expando = new ExpandoObject();
            IDictionary<string, object> dy = expando;
            //---------------------------------------------------------------------------------------------------------
            for (int j = 0; j < dr.Table.Columns.Count; j++)
            {
                dy[dr.Table.Columns[j].ColumnName] = dr[j];
            }
            //---------------------------------------------------------------------------------------------------------
            if (string.IsNullOrEmpty(jsonName))
            {
                return dy;
            }
            else
            {
                dynamic ret = new ExpandoObject();
                IDictionary<string, object> dyret = ret;
                dyret[jsonName] = expando;
                return ret;
            }
        }
        /// <summary>
        /// object 对象转dynamic
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static dynamic ToDynamic(this object obj)
        {
            if (obj == null || obj == DBNull.Value)
                return new { };
            if (obj is System.Dynamic.ExpandoObject)
                return obj;

            //dynamic expando = new ExpandoObject();
            //IDictionary<string, object> dy = expando;
            var dy = new MyDynamicObject();
            //---------------------------------------------------------------------------------------------------------
            if (obj is Newtonsoft.Json.Linq.JObject _jObject)//JSON Object
            {
                return ToDynamic(_jObject);
            }
            else if (obj is Newtonsoft.Json.Linq.JArray _ajObject)//JSON JArray
            {
                return ToDynamic(_ajObject);
            }
            else if (obj is System.Collections.IDictionary _dicObject)//IDictionary
            {
                foreach (object key in _dicObject.Keys)
                {
                    var val = _dicObject[key];
                    var dyPropName = key.ToString();
                    dy[dyPropName] = val;
                }
            }
            else if (obj is DataRow _drObject)//DataRow
            {
                return ToDynamic(_drObject);
            }
            else if (obj is DataTable _dtObject)//DataTable
            {
                return ToDynamic(_dtObject);
            }
            else//实体
            {
                return obj;
                //var properties = obj.GetType().GetProperties().ToList();
                //if (properties?.Count > 0)
                //{
                //    properties.ForEach(p =>
                //    {
                //        var val = p.GetValue(obj);
                //        dy[p.Name] = val;
                //    });
                //}
                //var fields = obj.GetType().GetFields().ToList();
                //if (fields?.Count > 0)
                //{
                //    fields.ForEach(f =>
                //    {
                //        var val = f.GetValue(obj);
                //        dy[f.Name] = val;
                //    });
                //}
            }

            return dy;
        }
        /// <summary>
        /// Newtonsoft.Json.Linq.JObject对象转dynamic
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static dynamic ToDynamic(this Newtonsoft.Json.Linq.JObject obj)
        {
            if (obj == null)
                return new { };

            //var expando = new MyDynamicObject();
            //IDictionary<string, object> dy = expando;
            var dy = new MyDynamicObject();
            foreach (var item in obj)
            {
                var val = item.Value;
                if (val != null)
                {
                    if (val is Newtonsoft.Json.Linq.JObject _sjObject)
                    {
                        dy[item.Key] = ToDynamic(_sjObject);
                    }
                    else if (val is Newtonsoft.Json.Linq.JArray _ajObject)
                    {
                        dy[item.Key] = ToDynamic(_ajObject);
                    }
                    else
                    {
                        dy[item.Key] = (val as Newtonsoft.Json.Linq.JValue).Value;
                    }
                    continue;
                }
                dy[item.Key] = null;
            }
            return dy;
        }
        /// <summary>
        /// Newtonsoft.Json.Linq.JArray 对象转dynamic
        /// </summary>
        /// <param name="jarray"></param>
        /// <returns></returns>
        public static dynamic ToDynamic(this Newtonsoft.Json.Linq.JArray jarray)
        {
            if (jarray == null)
                return new List<dynamic>();

            var expando = new List<dynamic>();
            foreach (var item in jarray)
            {
                if (item.HasValues)
                {
                    var val = item.Value<object>();
                    if (val != null)
                    {
                        if (val is Newtonsoft.Json.Linq.JObject _sjObject)
                        {
                            expando.Add(ToDynamic(_sjObject));
                        }
                        else if (val is Newtonsoft.Json.Linq.JArray _ajObject)
                        {
                            expando.Add(ToDynamic(_ajObject));
                        }
                        else
                        {
                            expando.Add(val);
                        }
                        continue;
                    }
                }
            }
            return expando;
        }
        #region IsJson
        public static bool IsJson(this string json)
        {
            int errIndex;
            return IsJson(json, out errIndex);
        }
        public static bool IsJson(this string json, out int errIndex)
        {
            errIndex = 0;
            json = json.Trim();
            if (string.IsNullOrEmpty(json) || json.Length < 2 ||
                ((json[0] != '{' && json[json.Length - 1] != '}') && (json[0] != '[' && json[json.Length - 1] != ']')))
            {
                return false;
            }
            CharState cs = new CharState();
            char c;
            for (int i = 0; i < json.Length; i++)
            {
                c = json[i];
                if (SetCharState(c, ref cs) && cs.childrenStart)//设置关键符号状态。
                {
                    string item = json.Substring(i);
                    int err;
                    int length = GetValueLength(item, true, out err);
                    cs.childrenStart = false;
                    if (err > 0)
                    {
                        errIndex = i + err;
                        return false;
                    }
                    i = i + length - 1;
                }
                if (cs.isError)
                {
                    errIndex = i;
                    return false;
                }
            }

            return !cs.arrayStart && !cs.jsonStart; //只要不是正常关闭，则失败
        }
        /// <summary>
        /// 获取值的长度（当Json值嵌套以"{"或"["开头时）
        /// </summary>
        private static int GetValueLength(string json, bool breakOnErr, out int errIndex)
        {
            errIndex = 0;
            int len = json.Length - 1;
            if (!string.IsNullOrEmpty(json))
            {
                CharState cs = new CharState();
                char c;
                for (int i = 0; i < json.Length; i++)
                {
                    c = json[i];
                    if (!SetCharState(c, ref cs))//设置关键符号状态。
                    {
                        if (!cs.jsonStart && !cs.arrayStart)//json结束，又不是数组，则退出。
                        {
                            break;
                        }
                    }
                    else if (cs.childrenStart)//正常字符，值状态下。
                    {
                        int length = GetValueLength(json.Substring(i), breakOnErr, out errIndex);//递归子值，返回一个长度。。。
                        cs.childrenStart = false;
                        cs.valueStart = 0;
                        //cs.state = 0;
                        i = i + length - 1;
                    }
                    if (breakOnErr && cs.isError)
                    {
                        errIndex = i;
                        return i;
                    }
                    if (!cs.jsonStart && !cs.arrayStart)//记录当前结束位置。
                    {
                        len = i + 1;//长度比索引+1
                        break;
                    }
                }
            }
            return len;
        }
        /// <summary>
        /// 字符状态
        /// </summary>
        private class CharState
        {
            internal bool jsonStart = false;//以 "{"开始了...
            internal bool setDicValue = false;// 可以设置字典值了。
            internal bool escapeChar = false;//以"\"转义符号开始了
            /// <summary>
            /// 数组开始【仅第一开头才算】，值嵌套的以【childrenStart】来标识。
            /// </summary>
            internal bool arrayStart = false;//以"[" 符号开始了
            internal bool childrenStart = false;//子级嵌套开始了。
            /// <summary>
            /// 【-1 未初始化】【0 取名称中】；【1 取值中】
            /// </summary>
            internal int state = -1;

            /// <summary>
            /// 【-2 已结束】【-1 未初始化】【0 未开始】【1 无引号开始】【2 单引号开始】【3 双引号开始】
            /// </summary>
            internal int keyStart = -1;
            /// <summary>
            /// 【-2 已结束】【-1 未初始化】【0 未开始】【1 无引号开始】【2 单引号开始】【3 双引号开始】
            /// </summary>
            internal int valueStart = -1;

            internal bool isError = false;//是否语法错误。

            internal void CheckIsError(char c)//只当成一级处理（因为GetLength会递归到每一个子项处理）
            {
                switch (c)
                {
                    case '{'://[{ "[{A}]":[{"[{B}]":3,"m":"C"}]}]
                        isError = jsonStart && state == 0;//重复开始错误 同时不是值处理。
                        break;
                    case '}':
                        isError = !jsonStart || (keyStart > 0 && state == 0);//重复结束错误 或者 提前结束。
                        break;
                    case '[':
                        isError = arrayStart && state == 0;//重复开始错误
                        break;
                    case ']':
                        isError = !arrayStart || (state == 1 && valueStart == 0);//重复开始错误[{},]1,0  正常：[111,222] 1,1 [111,"22"] 1,-2 
                        break;
                    case '"':
                        isError = !jsonStart && !arrayStart;//未开始Json，同时也未开始数组。
                        break;
                    case '\'':
                        isError = !jsonStart && !arrayStart;//未开始Json
                        break;
                    case ':':
                        isError = (!jsonStart && !arrayStart) || (jsonStart && keyStart < 2 && valueStart < 2 && state == 1);//未开始Json 同时 只能处理在取值之前。
                        break;
                    case ',':
                        isError = (!jsonStart && !arrayStart)
                            || (!jsonStart && arrayStart && state == -1) //[,111]
                            || (jsonStart && keyStart < 2 && valueStart < 2 && state == 0);//未开始Json 同时 只能处理在取值之后。
                        break;
                    default: //值开头。。
                        isError = (!jsonStart && !arrayStart) || (keyStart == 0 && valueStart == 0 && state == 0);//
                        if (!isError && keyStart < 2)
                        {
                            if ((jsonStart && !arrayStart) && state != 1)
                            {
                                //不是引号开头的，只允许字母 {aaa:1}
                                isError = c < 65 || (c > 90 && c < 97) || c > 122;
                            }
                            else if (!jsonStart && arrayStart && valueStart < 2)//
                            {
                                //不是引号开头的，只允许数字[1]
                                isError = c < 48 || c > 57;

                            }
                        }
                        break;
                }
                //if (isError)
                //{

                //}
            }
        }
        /// <summary>
        /// 设置字符状态(返回true则为关键词，返回false则当为普通字符处理）
        /// </summary>
        private static bool SetCharState(char c, ref CharState cs)
        {
            switch (c)
            {
                case '{'://[{ "[{A}]":[{"[{B}]":3,"m":"C"}]}]
                    #region 大括号
                    if (cs.keyStart <= 0 && cs.valueStart <= 0)
                    {
                        cs.CheckIsError(c);
                        if (cs.jsonStart && cs.state == 1)
                        {
                            cs.valueStart = 0;
                            cs.childrenStart = true;
                        }
                        else
                        {
                            cs.state = 0;
                        }
                        cs.jsonStart = true;//开始。
                        return true;
                    }
                    #endregion
                    break;
                case '}':
                    #region 大括号结束
                    if (cs.keyStart <= 0 && cs.valueStart < 2)
                    {
                        cs.CheckIsError(c);
                        if (cs.jsonStart)
                        {
                            cs.jsonStart = false;//正常结束。
                            cs.valueStart = -1;
                            cs.state = 0;
                            cs.setDicValue = true;
                        }
                        return true;
                    }
                    // cs.isError = !cs.jsonStart && cs.state == 0;
                    #endregion
                    break;
                case '[':
                    #region 中括号开始
                    if (!cs.jsonStart)
                    {
                        cs.CheckIsError(c);
                        cs.arrayStart = true;
                        return true;
                    }
                    else if (cs.jsonStart && cs.state == 1 && cs.valueStart < 2)
                    {
                        cs.CheckIsError(c);
                        //cs.valueStart = 1;
                        cs.childrenStart = true;
                        return true;
                    }
                    #endregion
                    break;
                case ']':
                    #region 中括号结束
                    if (!cs.jsonStart && (cs.keyStart <= 0 && cs.valueStart <= 0) || (cs.keyStart == -1 && cs.valueStart == 1))
                    {
                        cs.CheckIsError(c);
                        if (cs.arrayStart)// && !cs.childrenStart
                        {
                            cs.arrayStart = false;
                        }
                        return true;
                    }
                    #endregion
                    break;
                case '"':
                case '\'':
                    cs.CheckIsError(c);
                    #region 引号
                    if (cs.jsonStart || cs.arrayStart)
                    {
                        if (!cs.jsonStart && cs.arrayStart)
                        {
                            cs.state = 1;//如果是数组，只有取值，没有Key，所以直接跳过0
                        }
                        if (cs.state == 0)//key阶段
                        {
                            cs.keyStart = (cs.keyStart <= 0 ? (c == '"' ? 3 : 2) : -2);
                            return true;
                        }
                        else if (cs.state == 1)//值阶段
                        {
                            if (cs.valueStart <= 0)
                            {
                                cs.valueStart = (c == '"' ? 3 : 2);
                                return true;
                            }
                            else if ((cs.valueStart == 2 && c == '\'') || (cs.valueStart == 3 && c == '"'))
                            {
                                if (!cs.escapeChar)
                                {
                                    cs.valueStart = -2;
                                    return true;
                                }
                                else
                                {
                                    cs.escapeChar = false;
                                }
                            }

                        }
                    }
                    #endregion
                    break;
                case ':':
                    cs.CheckIsError(c);
                    #region 冒号
                    if (cs.jsonStart && cs.keyStart < 2 && cs.valueStart < 2 && cs.state == 0)
                    {
                        cs.keyStart = 0;
                        cs.state = 1;
                        return true;
                    }
                    #endregion
                    break;
                case ',':
                    cs.CheckIsError(c);
                    #region 逗号 {"a": [11,"22", ], "Type": 2}
                    if (cs.jsonStart && cs.keyStart < 2 && cs.valueStart < 2 && cs.state == 1)
                    {
                        cs.state = 0;
                        cs.valueStart = 0;
                        cs.setDicValue = true;
                        return true;
                    }
                    else if (cs.arrayStart && !cs.jsonStart) //[a,b]  [",",33] [{},{}]
                    {
                        if ((cs.state == -1 && cs.valueStart == -1) || (cs.valueStart < 2 && cs.state == 1))
                        {
                            cs.valueStart = 0;
                            return true;
                        }
                    }
                    #endregion
                    break;
                case ' ':
                case '\r':
                case '\n':
                case '\t':
                    if (cs.jsonStart && cs.keyStart <= 0 && cs.valueStart <= 0)
                    {
                        return true;//跳过空格。
                    }
                    break;
                default: //值开头。。
                    cs.CheckIsError(c);
                    if (c == '\\') //转义符号
                    {
                        if (cs.escapeChar)
                        {
                            cs.escapeChar = false;
                        }
                        else
                        {
                            cs.escapeChar = true;
                            //return true;
                        }
                    }
                    else
                    {
                        cs.escapeChar = false;
                    }
                    if (cs.jsonStart)
                    {
                        if (cs.keyStart <= 0 && cs.state <= 0)
                        {
                            cs.keyStart = 1;//无引号的
                        }
                        else if (cs.valueStart <= 0 && cs.state == 1)
                        {
                            cs.valueStart = 1;//无引号的
                        }
                    }
                    else if (cs.arrayStart)
                    {
                        cs.state = 1;
                        if (cs.valueStart < 1)
                        {
                            cs.valueStart = 1;//无引号的
                        }
                    }
                    break;
            }
            return false;
        }
        #endregion
        #endregion

        #region GetFieldPathValue
        /// <summary>
        /// 取对象属性值（如：id 、userInfo.id）
        /// </summary>
        /// <param name="input"></param>
        /// <param name="filedPath"></param>
        /// <param name="typeName"></param>
        /// <returns></returns>
        public static object GetFieldPathValue(this object input, string filedPath, string typeName = null)
        {
            if (filedPath.IsNullOrEmpty() || input.IsNullOrEmpty())
                return null;
            //if (typeName.IsNullOrEmpty()) typeName = "string";

            var filedPaths = filedPath.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
            object val = null;
            object newVal = input;
            for (var i = 0; i < filedPaths.Length; i++)
            {
                var filedName = filedPaths[i];
                if (filedName.IsNullOrEmpty()) continue;
                if (filedName.Contains("[") && filedName.Contains("]"))//取数组下标值
                {
                    var filedbame = filedName.Substring(0, filedName.IndexOf("["));
                    newVal = GetFieldValue(newVal, filedbame);
                    if (newVal != null)
                    {
                        var index = GetMatchValue(filedName).ChangeType<int>();
                        if (index >= 0 && newVal is System.Collections.IEnumerable array)
                        {
                            newVal = array.CastToList<object>()[i];
                        }
                    }
                }
                else//取属性值
                {
                    newVal = GetFieldValue(newVal, filedName);
                    if (newVal is string && newVal.NullToStr().IsJson())
                    {
                        newVal = Newtonsoft.Json.JsonConvert.DeserializeObject(newVal.NullToStr());
                    }
                    else if (newVal is Newtonsoft.Json.Linq.JValue _jValue && _jValue.Value is string && _jValue.Value.NullToStr().IsJson())
                    {
                        newVal = Newtonsoft.Json.JsonConvert.DeserializeObject(_jValue.Value.NullToStr());
                    }
                }

                if (i == filedPaths.Length - 1)
                {
                    val = newVal;
                }
            }
            if (val != null && typeName.IsNotNullOrEmpty())
            {
                var typeoff = typeName.FastGetType();
                if (typeoff != null)
                    return val.ChangeType(typeoff);
            }
            return val;
        }
        /// <summary>
        /// 取对象属性值
        /// </summary>
        /// <param name="input"></param>
        /// <param name="filedName"></param>
        /// <returns></returns>
        public static object GetFieldValue(this object input, string filedName)
        {
            if (filedName.IsNullOrEmpty() || input.IsNullOrEmpty())
                return null;
            filedName = filedName.Trim();
            if (input is Newtonsoft.Json.Linq.JObject _jObject)//JSON
            {
                foreach (var item in _jObject)
                {
                    if (item.Key.Trim().ToLower() != filedName.ToLower()) continue;
                    return item.Value;
                }
            }
            else if (input is Newtonsoft.Json.Linq.JArray _ajObject)
            {
                return input;
            }
            else if (input is System.Dynamic.ExpandoObject _eObject)//ExpandoObject
            {
                foreach (var item in _eObject)
                {
                    if (item.Key.Trim().ToLower() != filedName.ToLower()) continue;
                    return item.Value;
                }
            }
            else if (input is System.Collections.Generic.Dictionary<string, object> _dicObject)//Dictionary
            {
                foreach (var item in _dicObject)
                {
                    if (item.Key.Trim().ToLower() != filedName.ToLower()) continue;
                    return item.Value;
                }
            }
            else if (input is System.Collections.Generic.Dictionary<string, string> _dicstr)//Dictionary
            {
                foreach (var item in _dicstr)
                {
                    if (item.Key.Trim().ToLower() != filedName.ToLower()) continue;
                    return item.Value;
                }
            }
            else if (input is string)//string
            {
                return input;
            }
            else//实体
            {
                var property = input.GetType().GetProperties().ToList().Find(item => item.Name.Trim().ToLower() != filedName.ToLower());
                if (property != null)
                {
                    return property.GetValue(input, null);
                }
                var field = input.GetType().GetFields().ToList().Find(item => item.Name.Trim().ToLower() != filedName.ToLower());
                if (field != null)
                {
                    return field.GetValue(input);
                }
            }
            return null;
        }
        #endregion

        #region GetMatchValue
        /// <summary>
        /// 取中括号[]值
        /// </summary>
        /// <param name="template"></param>
        /// <param name="left"></param>
        /// <param name="right"></param>
        /// <returns></returns>
        public static string GetMatchValue(string template, string left = "[", string right = "]")
        {
            var rgx = new System.Text.RegularExpressions.Regex(@"(?i)(?<=\" + left + @")(.*)(?=\" + right + ")");//中括号[]
            var rt = rgx.Match(template).Value;//中括号[]
            return rt;
        }
        #endregion
    }
    #region MyDynamicObject
    public class MyDynamicObject : DynamicObject
    {
        // The inner dictionary.
        private Dictionary<string, object> _Values = new Dictionary<string, object>();

        // Getting a property.
        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            return _Values.TryGetValue(binder.Name, out result);
        }

        // Setting a property.
        public override bool TrySetMember(SetMemberBinder binder, object value)
        {
            _Values[binder.Name] = value;
            return true;
        }
        public object N(int fieldName)
        {
            return N(fieldName.ToString());
        }
        public object N(string fieldName)
        {
            if (_Values.TryGetValue(fieldName, out object result))
                return result;
            return null;
        }
        public string ToJson()
        {
            return Newtonsoft.Json.JsonConvert.SerializeObject(_Values);
        }
        /// <summary>
        /// this
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public object this[string name]
        {
            get { return _Values[name]; }
            set { _Values[name] = value; }
        }
        public Dictionary<string, object> Values
        {
            get { return this._Values; }
        }
    }
    #endregion
}
